package com.gopay.bis.icbc.ebank.operation;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.springframework.http.HttpStatus;

import cn.com.infosec.util.Base64;

import com.gopay.bis.common.util.BankLogUtils;
import com.gopay.bis.common.util.TransUtils;
import com.gopay.common.constants.bank.BankConstants;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.domain.bank.BaseMessage;
import com.gopay.common.domain.bank.icbc.ebank.query.res.CmsQueryB2CRes;
import com.gopay.common.domain.bank.icbc.ebank.query.res.EbQueryB2CRes;
import com.gopay.common.domain.bank.icbc.ebank.query.res.OutQueryB2CRes;
import com.gopay.common.domain.bank.icbc.ebank.query.res.PubQueryB2CRes;
import com.gopay.common.domain.bank.icbc.ebank.query.res.RdQueryB2CRes;
import com.gopay.common.exception.GopayException;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

public class IcbcB2cQuery {
    protected Log log = LogFactory.getLog(this.getClass());
    private static Log logger = LogFactory.getLog(IcbcB2cQuery.class);
	private final static String REQDATA = "reqData=";
	//订单查询地址
	private String url;
	//超时时间
	private int timeout;
	//设置编码
	private String sendEncoding;
	
	public synchronized String sendReq(Map<String, String> param) throws GopayException{
		long start =System.currentTimeMillis();
		BaseMessage baseMessage = new BaseMessage();
		baseMessage.setOutStlmCd(BankConstants.BANK_LOGO_ICBC); // 为了区分日志输出
		CloseableHttpClient httpClient = HttpClients.custom().setRetryHandler(new DefaultHttpRequestRetryHandler(1, false)).build();
		HttpPost method = new HttpPost(param.get("queryUrl") + "?userID="+ param.get("userID") + "&PackageID=" + param.get("PackageID")+ "&SendTime=" + param.get("SendTime"));
		CloseableHttpResponse response = null;
		try {
			RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(timeout).setConnectTimeout(timeout).setConnectionRequestTimeout(timeout).build();
			method.setHeader(HTTP.USER_AGENT, "Rich Powered/1.0");
			method.setHeader("Connection","close");
			method.setConfig(requestConfig);
			List<NameValuePair> nvps = new ArrayList<NameValuePair>();
			nvps.add(new BasicNameValuePair("Version", param.get("Version")));
			nvps.add(new BasicNameValuePair("TransCode", param.get("TransCode")));
			nvps.add(new BasicNameValuePair("BankCode", param.get("BankCode")));
			nvps.add(new BasicNameValuePair("GroupCIS", param.get("GroupCIS")));
			nvps.add(new BasicNameValuePair("ID", param.get("ID")));
			nvps.add(new BasicNameValuePair("PackageID", param.get("PackageID")));
			nvps.add(new BasicNameValuePair("Cert", ""));
			nvps.add(new BasicNameValuePair("reqData", param.get("reqData")));
			logger.info("reqData---------正确");
			method.setEntity(new UrlEncodedFormEntity(nvps));
			int statusCode = 0;
			response = httpClient.execute(method);
			logger.info("---------------去访问银行查询地址-------------------");
			statusCode = response.getStatusLine().getStatusCode();
			HttpEntity responseEntity = response.getEntity();
			
			if(statusCode == HttpStatus.FORBIDDEN.value()){
				for(int i=0;i<2;i++){
					//工行403拒绝访问,休眠3秒再访问一次
					TimeUnit.SECONDS.sleep(3);
					response = httpClient.execute(method);
					statusCode = response.getStatusLine().getStatusCode();
					responseEntity = response.getEntity();
					
					if((statusCode!=HttpStatus.FORBIDDEN.value())||i==1){
						break;
					}
				}
			}
			
			if (statusCode != HttpStatus.OK.value()) {
				BankLogUtils.printB2BHttpStatusCode(baseMessage, statusCode);
				return null;
			}
			String body = EntityUtils.toString(responseEntity);
			BankLogUtils.printB2CQuerySendLog(baseMessage, param);
			return body;
			
		} catch (Exception e) {
			BankLogUtils.printB2CQueryExceptionLog(baseMessage, e);
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E6037);
		} finally {
			try {
				if (response != null)
					response.close();
			} catch (IOException e) {
				// we need nothing to catch.
			}
		}
	}
	/**
	 * 截取返回消息体并做base64转码
	 * 
	 * @param String
	 * @return String
	 * 
	 * */
	public String decode(String responseBody) throws GopayException{
		BaseMessage baseMessage = new BaseMessage();
		baseMessage.setOutStlmCd(BankConstants.BANK_LOGO_ICBC); // 为了区分日志输出
		try {
			responseBody = responseBody.substring(REQDATA.length());
			// Base64转码
			String plainMessage = "";
			plainMessage = new String(Base64.decode(new String(responseBody.getBytes("GBK"), "UTF-8")), "GBK");
			BankLogUtils.printB2CQueryBlackLog(baseMessage, plainMessage);
			return plainMessage;
		} catch (Exception e) {
			BankLogUtils.printB2CQueryExceptionLog(baseMessage, e);
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E6039);
		}
	}
	
    /**
     * 解析工行对账返回报文(存在一笔订单返回多条记录情况)
     * 
     * @param responseBody
     * @return
     * @throws GopayException
     */
    public Object parse(String plainMessage) throws GopayException {
        CmsQueryB2CRes res = new CmsQueryB2CRes();
        // 订单节点
        String cons = "<rd>";
        String con = "</rd>";
        String result = "";

        if (plainMessage.indexOf(cons) == -1) {
            // 不包含订单明细(订单不存在情况)
            return getXml(plainMessage);
        } else {
            // 包含一笔或多笔订单明细
            int cnt = 0;
            int count = 0;
            while ((count = plainMessage.indexOf(cons, count)) != -1) {
                count = count + cons.length();
                cnt++;
            }

            if (cnt == 1) {
                // 只包含一笔订单明细
                return getXml(plainMessage);
            } else {
                // 包含多笔订单明细
                EbQueryB2CRes eb = new EbQueryB2CRes();
                PubQueryB2CRes pub = new PubQueryB2CRes();
                OutQueryB2CRes out = new OutQueryB2CRes();
                RdQueryB2CRes rd = new RdQueryB2CRes();
                pub.setRetCode("0"); // 查询成功
                rd.setResult("3"); // 默认不处理

                while (plainMessage.indexOf(cons) != -1) {
                    result = TransUtils.getMsgField("<Result>", "</Result>", plainMessage);
                    if ("0".equals(result) || "1".equals(result)) {
                        // 订单成功
                        rd.setResult(result); // 订单成功
                        rd.setOrderAmt(TransUtils.getMsgField("<OrderAmt>", "</OrderAmt>", plainMessage));
                    }
                    plainMessage = plainMessage.substring(plainMessage.indexOf(con) + 5);
                }
                out.setRd(rd);
                eb.setPub(pub);
                eb.setOut(out);
                res.setEb(eb);
                log.error("ICBC B2C QUERY RES PARSE: " + ToStringBuilder.reflectionToString(rd));
                return res;
            }
        }
    }

    private CmsQueryB2CRes getXml(String plain) {
        CmsQueryB2CRes res = new CmsQueryB2CRes();
        // 将XML字符串转换为对象
        XStream xs = new XStream(new DomDriver());
        xs.autodetectAnnotations(true);
        xs.toXML(res);
        res = (CmsQueryB2CRes) xs.fromXML(plain);
        return res;
    }
    
	public void setUrl(String url) {
		this.url = url;
	}

	public void setTimeout(int timeout) {
		this.timeout = timeout;
	}

	public void setSendEncoding(String sendEncoding) {
		this.sendEncoding = sendEncoding;
	}
}
